﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
using TVA;
using TVA.Configuration;

namespace PmuRegistry.Data
{
	public class DataConnection : IDisposable
	{
		#region [ Members ]
		
		IDbConnection m_connection;
		private bool m_disposed;

		#endregion

		#region [ Constructors ]

		/// <summary>
		/// Creates a new <see cref="DataConnection"/>.
		/// </summary>
		public DataConnection()
		{
			// Only need to establish data types and load settings once
			if (m_connectionType == null || string.IsNullOrEmpty(m_connectionString))
			{
				// Load connection settings from the system settings category				
				ConfigurationFile config = ConfigurationFile.Current; //new ConfigurationFile("~/web.config", ApplicationType.Web);
				CategorizedSettingsElementCollection configSettings = config.Settings["systemSettings"];

				string dataProviderString = configSettings["DataProviderString"].Value;
				m_connectionString = configSettings["ConnectionString"].Value;

				if (string.IsNullOrEmpty(m_connectionString))
					throw new NullReferenceException("ConnectionString setting was undefined.");

				if (string.IsNullOrEmpty(dataProviderString))
					throw new NullReferenceException("DataProviderString setting was undefined.");

				// Attempt to load configuration from an ADO.NET database connection
				Dictionary<string, string> settings;
				string assemblyName, connectionTypeName, adapterTypeName;
				Assembly assembly;

				settings = dataProviderString.ParseKeyValuePairs();
				assemblyName = settings["AssemblyName"].ToNonNullString();
				connectionTypeName = settings["ConnectionType"].ToNonNullString();
				adapterTypeName = settings["AdapterType"].ToNonNullString();

				if (string.IsNullOrEmpty(connectionTypeName))
					throw new NullReferenceException("Database connection type was undefined.");

				if (string.IsNullOrEmpty(adapterTypeName))
					throw new NullReferenceException("Database adapter type was undefined.");

				//Assembly assembly;
				//string assemblyName = "System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
				//string connectionTypeName = "System.Data.SqlClient.SqlConnection";
				//string adapterTypeName = "System.Data.SqlClient.SqlDataAdapter";
				//m_connectionString = "Data Source=RGOCDSQL;Initial Catalog=openPDC;User Id=openPDCManagerUser;Password=NXJCt0XD";

				assembly = Assembly.Load(new AssemblyName(assemblyName));
				m_connectionType = assembly.GetType(connectionTypeName);
				m_adapterType = assembly.GetType(adapterTypeName);
			}

			// Open ADO.NET provider connection
			m_connection = (IDbConnection)Activator.CreateInstance(m_connectionType);
			m_connection.ConnectionString = m_connectionString;
			m_connection.Open();
		}

		/// <summary>
		/// Releases the unmanaged resources before the <see cref="DataConnection"/> object is reclaimed by <see cref="GC"/>.
		/// </summary>
		~DataConnection()
		{
			Dispose(false);
		}

		#endregion

		#region [ Properties ]

		/// <summary>
		/// Gets an open <see cref="IDbConnection"/> to configured ADO.NET data source.
		/// </summary>
		public IDbConnection Connection
		{
			get
			{
				return m_connection;
			}
		}

		#endregion

		#region [ Methods ]

		/// <summary>
		/// Releases all the resources used by the <see cref="DataConnection"/> object.
		/// </summary>
		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		/// <summary>
		/// Releases the unmanaged resources used by the <see cref="DataConnection"/> object and optionally releases the managed resources.
		/// </summary>
		/// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
		protected virtual void Dispose(bool disposing)
		{
			if (!m_disposed)
			{
				try
				{
					if (disposing)
					{
						if (m_connection != null)
							m_connection.Dispose();
						m_connection = null;
					}
				}
				finally
				{
					m_disposed = true;  // Prevent duplicate dispose.
				}
			}
		}

		#endregion

		#region [ Static ]

		// Static Fields
		static Type m_connectionType;
		static Type m_adapterType;
		static string m_connectionString;

		#endregion
	}
}
